// 此文件被用于做“路由鉴权”（即路由级别的权限控制）（注：“鉴权”即“设置权限”（也就是是设置“某个路由能否被访问”，以及该路由在什么情况下“能被访问”和“不能被访问”））
import router from "@/router"
// 导入“nprogress”插件↓
import nprogress from "nprogress"
// 导入“nprogress”插件的“样式文件”↓
import "nprogress/nprogress.css"
import setting from "@/setting"
nprogress.configure({
    showSpinner: false, // 不显示加载图标
})
console.log("路由鉴权文件被加载了")
// 导入并获取存储了用户信息的仓库，通过被存储在该仓库中的数据“token”来判断“用户是否已经登录”↓
import useUserStore from "@/store/modules/user"
import pinia from "@/store"
let userStore = useUserStore(pinia)
// 注：如果上面的这行代码中开发者不把“pinia”作为参数传递给函数，则浏览器在执行下面的这一行代码时，控制台中会输出警告，提示开发者“是否忘记安装pinia了”↓
console.log(userStore)
// 解释什么是“路由守卫”：路由守卫就是在项目中的任意两个路由间发生跳转时都会被触发执行的钩子函数。它可以被用来在路由跳转前后做一些事情（比如：在进入某个页面之前先判断用户是否登录了）
// 路由守卫一共有三种：全局前置守卫、全局后置守卫、路由独享的守卫（也就是组件内的守卫（即在某个路由单独设置一个守卫））
// 全局前置守卫（它是在用户访问某个路由之前被调用的钩子函数）↓
router.beforeEach(async (to: any, from: any, next: any) => {
    // 设置页面标题（注：此处的“标题”是指在当前页面在浏览器的“标签”（选项卡）上显示的标题）↓
    // document.title = `硅谷甄选运营平台 - ${to.meta.title}`
    document.title = `${setting.title} - ${to.meta.title}`
    console.log("全局前置守卫被触发了")
    // 注：在此处，参数“to”表示的是“用户即将要访问的路由对象”，参数“from”表示的是“用户访问的上一个路由对象”，参数“next”是“路由守卫的放行函数”，它有两个作用：1.调用它可以继续执行路由跳转；2.如果想中断当前路由的跳转，则可以传递一个参数给它（比如：next(false)）
    console.log("即将要访问的路由对象：", to)
    console.log("用户访问的上一个路由对象：", from)
    console.log("路由守卫的放行函数：", next)
    // 在任意路由之间发生跳转时实现“加载进度条”（借助插件“nprogress”来实现）↓
    nprogress.start()
    // 获取“token”，以判断“用户是否已经登录”↓
    let token = userStore.token
    // 获取仓库中存储的用户名↓
    let username = userStore.username
    if (token) {
        // 如果进入了这个代码块，则说明用户已经登录了
        if (to.path == "/login") {
            // 如果进入了这个代码块，则说明用户已经登录了，但又想访问“登录”页面
            next({ path: "/" })
        } else {
            // 如果进入了这个代码块，则说明用户已经登录了，访问的目标是除登录页面以外的其他页面
            if (username) {
                // 如果进入了这个代码块，则说明用户已经登录了，并且仓库中已经存储了包含用户名在内的用户信息，这时可以直接放行，让用户访问目标页面↓
                next()                
            } else {
                // 如果进入了这个代码块，则说明虽然用户已经登录了，但仓库中还没有存储用户信息（虽然这种情况一般不会发生，但是由于用户信息被存储在仓库中，且仓库是利用普通的JS对象来保存数据，这种方法不会持久化保存数据，有可能会发生因用户登录后“刷新页面”而导致“用户信息被丢失”的情况，所以在此处需要补充发生这种情况后的处理方法），这时需要重新给接口发送请求，以获取用户信息↓
                try {
                    // 重新给接口发送请求，以获取用户信息↓
                    await userStore.getUserInfomation()
                    // 等获取到用户信息后，再放行↓
                    // next()
                    // 使用上面这行代码↑时有可能发生的意外情况：刷新页面时当前页面的所在路由是“异步路由”，可能会由于“虽然已获取到用户信息，但是异步路由还未被加载完毕”而导致出现“页面空白”的情况，所以需要改用下面的这行代码↓
                    next({...to}) // 这行代码可以保证“目标路由被加载完毕”
                    /* 注：“文心快码”解释了上面的这一行代码为什么可以保证“目标路由被加载完毕”：在您提供的代码中，next({...to})被用于全局前置守卫中，当用户已经登录且用户信息已存在时，确保目标路由被加载完毕。这里的{...to}使用了ES6的扩展运算符，用于创建一个to路由对象的浅拷贝。
                    为什么next({...to})可以保证目标路由被加载完毕：1.重新触发导航解析：在某些情况下，如异步路由或组件的延迟加载，直接调用next()可能导致路由组件还未完全加载，页面出现空白。通过传递{...to}给next，Vue Router会重新解析目标路由，包括其异步组件，从而确保路由被完全加载。
                    2.避免副作用：在某些实现中，直接调用next()可能不会触发路由的重新解析，特别是当路由对象（to）在守卫执行过程中被修改时。使用{...to}可以确保传递给next的是一个全新的路由对象，避免了潜在的副作用。
                    3.触发路由更新：在某些特定场景，如动态路由或依赖路由参数的组件，直接调用next()可能不会触发路由的更新。通过传递{...to}，可以强制Vue Router重新处理路由，确保所有与路由相关的逻辑（如路由参数、查询字符串、路由元信息等）都被正确应用。
                    在您的代码中，next({...to})被用于确保在用户已登录且用户信息已存在的情况下，目标路由被完全加载。特别是当路由组件是异步加载的，或者路由的解析依赖于某些异步操作时，这种做法可以避免页面空白或路由加载不完整的问题。
                    结论：next({...to})在Vue Router的路由守卫中被用于确保目标路由被完全加载，特别是在处理异步路由或组件的延迟加载时。通过重新触发路由解析，它可以避免潜在的路由加载问题，确保用户导航到正确的页面。↑ */
                } catch (error) {
                    // 如果进入了这个代码块，那么说明：1.“token”虽然存在，但已经过期了（也就是相当于用户还没有登录（因为用户凭原来的token已无法获取到用户信息））；2.用户手动修改或删除了被存储在“本地存储”中的token。发生这两种情况时都需要让用户重新登录↓
                    // userStore.afunctionForHandleUserLogout()
                    await userStore.afunctionForHandleUserLogout()
                    next({ path: "/login", query: { redirect: to.path } })
                }
            }
        }
    } else {
        // 如果进入了这个代码块，则说明用户还没有登录
        if (to.path == "/login") {
            next()
        } else {
            next({ path: "/login", query: { redirect: to.path } })
        }
    }

    // next()
})
// 全局后置守卫（它是在用户已经把某个路由访问完毕之后被调用的钩子函数）↓
router.afterEach((to: any, from: any) => {
    console.log("全局后置守卫被触发了")
    nprogress.done()
})
// 实现“路由级别的权限控制”（即“鉴权”（即“设置路由组件的访问权限”））↓
// 目前项目中拥有的全部路由组件：登录、404、任意路由、首页、数据大屏、权限管理（含3个子路由）、商品管理（含4个子路由）
// 在用户“未登录”时：用户只能访问“登录”和“404”页面，访问其他页面时会被重定向到“登录”页面；在用户“已登录”时：用户不能访问“登录”页面，访问“登录”页面时会被重定向到首页，其他页面则可以正常访问